

package functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.program.geneSetAnalysis;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.parsers.SimilarityFileParser;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.program.Argument;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.program.Program;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.units.Gene;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.units.GeneLibrary;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.utils.FileUtils;



/**
 *
 * @author Jamie MacPherson
 */
public class GeneSetAnalysisProgram extends Program{

    // the gene library,  a repository for all gene objects
    private GeneLibrary library;

    /**
     * A required method of the <code>Program</code> interface that runs the program.
     * This method runs an analysis of the semantic similarity between sets of genes that are
     * in the file or folder that was specified on the command line (command line option -d).
     */
    @Override
    public void run() {

        File resultsFolder = null;
        try {
            resultsFolder = getResultsFile();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
            System.exit(0);
        }

        System.out.println("getting all semantic similarities from file");
        SimilarityFileParser similarityFileParser = new SimilarityFileParser();
        try {
            similarityFileParser.readAllSimilarities((File) argumentMap.get(Argument.SIMILARITIESFILE));
        } catch (IOException ex) {
            System.out.println("reading similarity file failed");
            System.out.println("exiting program");
            ex.printStackTrace();
            System.exit(0);
        }
        library = similarityFileParser.getGeneLibrary();

        File subjectGeneSetFile = (File) argumentMap.get(Argument.SUBJECTGENESFILE);
        
        if (subjectGeneSetFile.isDirectory()) {
            for (File geneSetFile : subjectGeneSetFile.listFiles()) {
                runForSingleFile(geneSetFile, similarityFileParser, resultsFolder);
            }
        } else {
            runForSingleFile(subjectGeneSetFile, similarityFileParser, resultsFolder);
        }

    }

   /**
    * Given an input file that contains gene sets (lists of gene IDs), the method will parse the file and return a map
    * with a the gene lists, containing <code>Gene</code> objects (values) and gene set identifiers (keys).
    * @param input the file to parse.
    * @return the map of gene lists.
    */

    private Map<String, List<Gene>> getGeneSets(File input) {
        BufferedReader reader = FileUtils.getBufferedReader(input);
        Map<String, List<Gene>> geneSets = new HashMap<String, List<Gene>>();
        String line;

        try {
            String current = null;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("#")) {
                    current = line.substring(1);
                    geneSets.put(current, new ArrayList<Gene>());
                } else {
                    Gene g = library.getGene(line);
                    if(!geneSets.get(current).contains(g)){
                        geneSets.get(current).add(g);
                    }
                }
            }
            reader.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return geneSets;
    }

    /**
     * Runs tha gene set analysis for a a subject gene set file, given a <code>SimilarityFileParser</code> that contains
     * the semntic similarity informatin between genes, and a results folder as a destination for the results files.
     * @param subjectGeneSetFile a file containing gene lists to be analysed.
     * @param distanceFileParser an object that contains the semantic similarity between genes data.
     * @param resultsFolder a folder that will be the destination for the results file(s).
     */
    private void runForSingleFile(File subjectGeneSetFile, SimilarityFileParser similarityFileParser, File resultsFolder) {

        System.out.println("running stats on file: " + subjectGeneSetFile.getName());
        Map<String, List<Gene>> geneSets = getGeneSets(subjectGeneSetFile);
        System.out.println("there are "+geneSets.size()+" gene sets in this file");
        if(geneSets.size()>1){
            GeneSetAnalysis analysis = new GeneSetAnalysis(geneSets, similarityFileParser, getNoOfThreads(), resultsFolder);
            analysis.setRunInternalOnly(true);
            analysis.run();
        }
    }

    /**
     * Returns the number of threads in which the program should run, obtained from the <code>ArgumentMap</code>
     * that holds the command-line argument data. Number of threads is specified on the command line using the
     * -t option.
     * @return an integer value that is equal to the number of threads in which the analysis will run.
     */
    private int getNoOfThreads() {
        Integer noOfThreads = (Integer) argumentMap.get(Argument.THREADS);
        if(noOfThreads==null){
            return 1;
        } return noOfThreads;
    }
    /**
     * Returns the results folder to whcih output files should be written, obtained from the <code>ArgumentMap</code>
     * that holds the command-line argument data. The results folder is specified on the command line using the
     * -r option.
     * @return a File that will be the destination for the program output.
     */
    private File getResultsFile() throws FileNotFoundException{
        File resultsFile = (File) argumentMap.get(Argument.RESULTSFILE);
        if(!resultsFile.exists()){
            System.out.println("the results folder, "+resultsFile.getPath()+", that you specified does not exists");
            System.out.println("exiting program");
        }
        return resultsFile;
    }
}
